package com.story.rpc.util;

import cn.hutool.core.thread.ThreadFactoryBuilder;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;
import java.util.concurrent.*;
@Slf4j
public class ThreadPoolUtils {
    private static final Map<String, ExecutorService> THREAD_POOL_CACHE = new ConcurrentHashMap<>();
    // CPU 核心数的数量
    private static final int CPU_NUM = Runtime.getRuntime().availableProcessors();

    // IO密集型 和 CPU密集型
    private static final int CPU_INTENSIVE_NUM = CPU_NUM + 1;
    private static final int IO_INTENSIVE_NUM = CPU_NUM * 2;
    private static final int DEFAULT_KEEP_ALIVE_TIME = 60;
    private static final int DEFAULT_QUEUE_SIZE = 128;

    public static ExecutorService createCpuIntensiveThreadPool(
            String poolName
    ){
        return createThreadPool(CPU_INTENSIVE_NUM,poolName);
    }
    public static ExecutorService createIoIntensiveThreadPool(
            String poolName
    ){
        return createThreadPool(IO_INTENSIVE_NUM,poolName);
    }
    public static ExecutorService createThreadPool(
            int corePoolSize,
            String poolName
    ){
        return createThreadPool(corePoolSize,corePoolSize,poolName);
    }

    public static ExecutorService createThreadPool(
            int corePoolSize,
            int maxPoolSize,
            String poolName
    ){
        return createThreadPool(corePoolSize,maxPoolSize,DEFAULT_KEEP_ALIVE_TIME,DEFAULT_QUEUE_SIZE,poolName);
    }

    public static ExecutorService createThreadPool(
            int corePoolSize,
            int maxPoolSize,
            long keepAliveTime,
            int queueSize,
            String poolName
    ){

        return createThreadPool(corePoolSize,maxPoolSize,keepAliveTime,queueSize,poolName,false);
    }
    public static ExecutorService createThreadPool(
            int corePoolSize,
            int maxPoolSize,
            long keepAliveTime,
            int queueSize,
            String poolName,
            boolean isDaemon
    ){
        if(THREAD_POOL_CACHE.containsKey(poolName)){
            return THREAD_POOL_CACHE.get(poolName);
        }
        ExecutorService executorService = new ThreadPoolExecutor(
                corePoolSize,
                maxPoolSize,
                keepAliveTime,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(queueSize),
                createThreadFactory(poolName,isDaemon)
        );
        log.info("创建线程池:{}",poolName);
        THREAD_POOL_CACHE.put(poolName, executorService);
        return executorService;
    }
    /**
     *
     * 创建ThreadFactory的工具方法
     * 用户线程：执行应用程序主要任务的线程，执行应用程序的主要功能
     * 守护线程：为用户线程提供服务的线程，通常用于执行后台任务(非核心)，如垃圾回收、内存管理、监控；垃圾回收器就是典型的守护线程
     * 线程池是一组预先创建的线程，用于执行任务。通过重用这些线程，可以减少线程创建和销毁的开销，提高应用程序的性能和响应速度。
     * 线程工厂（ThreadFactory）用于创建和配置Thread对象的属性。通过实现或使用线程工厂，
     *      你可以灵活地设置线程的各种属性，如名称前缀、是否为守护线程、优先级等。这有助于更好地管理和调试线程池中的线程。
     * @param poolName  线程池的名称前缀
     * @param isDaemon  是否是守护线程
     * @return
     */
    public static ThreadFactory createThreadFactory(String poolName,boolean isDaemon){
        ThreadFactoryBuilder threadFactoryBuilder = ThreadFactoryBuilder.create().setDaemon(isDaemon);
        if(StrUtil.isBlank(poolName)){
            return threadFactoryBuilder.build();
        }
        return threadFactoryBuilder.setNamePrefix(poolName).build();
    }
    public static ThreadFactory createThreadFactory(String poolName){

        return createThreadFactory(poolName,false);
    }
    public static void shutdownAll(){
        THREAD_POOL_CACHE.entrySet().parallelStream()
                .forEach(entry->{
                    String poolName = entry.getKey();
                    ExecutorService executorService = entry.getValue();
                    log.info("{},线程池开始停止...",poolName);
                    try{
                        if(executorService.awaitTermination(10,TimeUnit.SECONDS)){
                            log.info("线程池已停止",poolName);
                        }else{
                            log.info("{},线程池10s内未停止，强制停止",poolName);
                            executorService.shutdownNow();
                        }
                    } catch (InterruptedException e) {
                        log.error("{},线程池停止异常",poolName);
                        executorService.shutdownNow();
                    }
                });
    }
}
